﻿using System;
using Renci.SshNet;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace HPiLO2
{
    [Serializable()]
    public class iLOClient
    {
        public string URL { get; set; }

        public string UserName { get; set; }

        public string Password { get; set; }

        public string FriendlyName { get; set; }

        public bool Enabled { get; set; }

        public int Port { get; set; }

        public bool Connected = false;
        public bool PowerOn = false;

        public bool SSH { get; set; }

        [NonSerialized]
        private CommsClient _Comm;

        public bool UID = false;

        /// <summary>
        /// Create a new iLOClient
        /// </summary>
        /// <param name="url">URL / IP of the device</param>
        /// <param name="password">Password for login</param>
        /// <param name="friendlyname">Friendly Name for device, if "" = url</param>
        /// <param name="username">Username for device, if "" = Administrator</param>
        /// <param name="enabled">Enabled state of device - default = true</param>
        public iLOClient(string url, string password, string friendlyname = "", string username = "", bool enabled = true, bool _SSH = false)
        {
            URL = url; Password = password;
            FriendlyName = friendlyname == "" ? url : friendlyname;
            UserName = username == "" ? "Administrator" : username;
            Enabled = enabled;
            SSH = _SSH;
            if (SSH)
            {
                _Comm = new TelnetLib();
                Port = 22;
            }
            else
            {
                _Comm = new TelnetLib();
                Port = 23;
            }
        }

        /// <summary>
        /// Update Details and
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="state"></param>
        public void Refresh(int cmd = 0, bool state = false)
        {
            try
            {

               int res = InitComms();
                if (res == 0)
                    Connected = true;
                if (res == -1)
                {
                    Connected = false;
                    return;
                }
                PowerOn = _Comm.RunBolCommand("power");
                UID = _Comm.RunBolCommand("uid");

                if (cmd > 0)
                {
                    switch (cmd)
                    {
                        case 1:

                            _Comm.RunCommand("power " + ((!PowerOn).ToString() == "True" ? "on" : "off"));

                            PowerOn = !PowerOn;
                            break;

                        case 2:
                            _Comm.RunCommand("power reset");

                            break;

                        case 3:
                            if (state)
                            {
                                _Comm.RunCommand("uid on");
                            }
                            else
                            {
                                _Comm.RunCommand("uid off");
                            }
                            UID = state;
                            break;
                        default:
                            break;
                    }
                }
                _Comm.Close();
            }
            catch
            {
            }
        }
        private int InitComms()
        {
            if (SSH)
            {
                if (Port == 0) // correct invalid port
                {
                    Port = 2;
                }
                _Comm = new SSHLib();
            }
            else // fallback to telnet
            {
                if (Port == 0) // correct invalid port
                {
                    Port = 23;
                }
                _Comm = new TelnetLib();
            }

             return _Comm.Connect(URL, Port, UserName, Password);
        }
        public void GetDetailedinformation()
        {
            InitComms();
            _Comm.RunCommand("cd /system1");
            string Targets = _Comm.RunCommand("show");
            Targets = Targets.Substring(Targets.IndexOf("Targets") + "Targets".Length).Replace("\r\n","\r");
            List<string> Details = new List<string> { };
            List<int> Maximums = new List<int> { };
            List<string> Properties = new List<string> { };
            
            bool probFound = false;
            foreach(string line in Targets.Split('\r'))
            {
                if (line.Trim().Length > 2)//valid line not a empty
                {
                    string a = "";
                    if (!probFound)
                    {
                        foreach (char c in line)
                        {
                            if (char.IsLetter(c) || c=='_')
                                a += c.ToString();
                        }
                        if (a == "Properties")
                        {
                            probFound = true;
                        }
                        else
                        {
                            if (Details.IndexOf(a) == -1)
                            {
                                Details.Add(a);
                                Maximums.Add(1);
                            }
                            else
                            {
                                int index = Details.IndexOf(a);
                                Maximums[index] = int.Parse(line.Trim().Replace(a, ""));// grab the number off the end :)
                            }
                        }
                    }
                    else
                    {
                        if (line.Contains("[D") || line.Contains("hpiLO->")||line.Contains("Verbs") || line.Contains("cd version exit show reset set start stop"))
                        {
                        }
                        else
                        {
                            Properties.Add(line.Trim());
                        }
                    }
                }
            }
            //got the details we want

            TabControl DetailsTab = new TabControl();
            List<TabPage> Pages = new List<TabPage> { };
            Pages.Add(new TabPage("Overview"));
            ListBox deets = new ListBox();
            foreach (string s in Properties)
            {
               deets.Items.Add( s.Replace("=", "\t \t : "));

            }
            Pages[0].Controls.Add(deets);

            for(int z=0;z<Details.Count;z++)
            {
                Pages.Add(new TabPage(Details[z]));
                ListBox _list = new ListBox();
                List<string> Information = new List<string> { };
                for (int i = 1; i <= Maximums[z]; i++)
                {
                    string source;
                    if (Details[z] == "drives")
                    {
                        source = _Comm.RunCommand("show " + Details[z]);
                    }
                    else
                    {
                        source = _Comm.RunCommand("show " + Details[z] + i.ToString());
                    }
                   
                    source = source.Substring(source.IndexOf("Properties") + "Properties".Length);
                   source =  source.Substring(0, source.IndexOf("Verb") - 4).Replace("\r\n","\r");
                   Information.Add("\t" + Details[z] + i.ToString());
                   foreach (string s in source.Split('\r'))
                   {
                       if (s.Trim().Length > 4)
                       {
                           Information.Add("\t" + s);
                       }
                   }
                }
                _list.Items.AddRange(Information.ToArray());
                Pages[Pages.Count - 1].Controls.Add(_list);

            }

            Form _detailsForm = new Form();
            _detailsForm.Text = "Details: "+ FriendlyName;
            DetailsTab.TabPages.AddRange(Pages.ToArray());
            
            _detailsForm.Controls.Add(DetailsTab);
            _detailsForm.Width = 805;
            _detailsForm.Height = 605;
            _detailsForm.PerformLayout();
            //BEWARE HORROR CODE BELOW TO SET SIZES
            for (int i = 0; i < _detailsForm.Controls.Count; i++)
            {
                _detailsForm.Controls[i].Width = 800;
                _detailsForm.Controls[i].Height = 600;
                _detailsForm.Controls[i].Top = 2;
                _detailsForm.Controls[i].Left = 2;
                for(int x=0;x<_detailsForm.Controls[i].Controls.Count;x++)
                {
            _detailsForm.Controls[i].Controls[x].Width = 800;
            _detailsForm.Controls[i].Controls[x].Height = 600;
            _detailsForm.Controls[i].Controls[x].Top = 0;
            _detailsForm.Controls[i].Controls[x].Left = 0;
            _detailsForm.Controls[i].Controls[x].PerformLayout();
            for (int y = 0; y < _detailsForm.Controls[i].Controls[x].Controls.Count; y++)
            {
                _detailsForm.Controls[i].Controls[x].Controls[y].Width = 800;
                _detailsForm.Controls[i].Controls[x].Controls[y].Height = 600;
                _detailsForm.Controls[i].Controls[x].Controls[y].Top = 0;
                _detailsForm.Controls[i].Controls[x].Controls[y].Left = 0;
                _detailsForm.Controls[i].Controls[x].Controls[y].PerformLayout();
            }
                }
                _detailsForm.Controls[i].PerformLayout();
            }
         
         //END HORROR CODE
            
           
            _detailsForm.PerformLayout();

            _detailsForm.Show();
            _detailsForm.Focus();
        }
    }

    #region Communication librarys

    internal interface CommsClient
    {
        string RunCommand(string command);

        int Connect(string url, int port, string username, string password);

        void Close();

        bool RunBolCommand(string cmd);
    }

    public class TelnetLib : CommsClient
    {
        private MinimalisticTelnet.TelnetConnection telnet;

        public int Connect(string url, int port, string username, string password)
        {
            try
            {
                telnet = new MinimalisticTelnet.TelnetConnection(url, port);
                return 0;
            }
            catch
            {
                return -1;
            }
        }

        /// <summary>
        /// Closes the connection
        /// </summary>
        public void Close()
        {
            telnet.Close();
        }

        public string RunCommand(string cmd)
        {
            WriteLine(cmd);
            System.Threading.Thread.Sleep(500);
            return Read();
        }

        /// <summary>
        /// Writes a line of text to the connection
        /// </summary>
        /// <param name="text"></param>
        private void WriteLine(string text)
        {
            telnet.WriteLine(text);
        }

        /// <summary>
        /// Reads the entire buffer from the connection
        /// </summary>
        /// <returns></returns>
        private string Read()
        {
            return telnet.Read();
        }

        public bool RunBolCommand(string cmd)
        {
            string ans = RunCommand(cmd);

            ans = ans.Substring(ans.IndexOf(" currently: ") + " currently: ".Length);
            ans = ans.Substring(0, ans.IndexOf("\r\n")).ToLower();

            if (ans == "on")
                return true;
            if (ans == "off")
                return false;
            return false;
        }
    }

    public class SSHLib : CommsClient
    {
        private Renci.SshNet.SshClient shell;

        public int Connect(string url, int port, string username, string password)
        {
            try
            {
                shell = new SshClient(url, username, password);
                shell.Connect();

                return 0;
            }
            catch
            {
                return -1;
            }
        }

        public void Close()
        {
            shell.Disconnect();
        }

        public string RunCommand(string cmd)
        {
            var res = shell.RunCommand(cmd);
            res.Execute();
          //  System.Threading.Thread.Sleep(50);
            return res.Result;
        }

        public bool RunBolCommand(string cmd)
        {
            string ans = RunCommand(cmd);

            ans = ans.Substring(ans.IndexOf(" currently: ") + " currently: ".Length);
            ans = ans.Substring(0, ans.IndexOf("\r\n")).ToLower();

            if (ans == "on")
                return true;
            if (ans == "off")
                return false;
            return false;
        }
    }

    #endregion Communication librarys
}